; 硬盘版 IPL（读取10个柱面，匹配书中“读入10个柱面”逻辑）
org 0x7c00          ; BIOS 加载到 0x7c00 执行

; 初始化段寄存器
mov ax, 0          
mov ds, ax        
mov es, ax        
mov ss, ax        
mov sp, 0x7c00     ; 栈指针指向 IPL 下方

; （可选）打印启动信息
mov si, msg_boot   
call putstr       

; --------------------------
; 核心：从硬盘读取 10 个柱面（CHS 模式）
; 目标：读取柱面0~9、磁头0~1、扇区2~18（共 10×2×17 = 340 个扇区）
; 加载到内存 0x8200 开始的区域（ES:BX = 0x0820:0x0000）
; --------------------------
mov ax, 0x0820     
mov es, ax         ; 目标内存段地址 = 0x0820（物理地址 0x8200）
mov ch, 0          ; 起始柱面 = 0
mov dh, 0          ; 起始磁头 = 0
mov cl, 2          ; 起始扇区 = 2（1-based，跳过启动扇区自身）
mov dl, 0x80       ; 书中是软盘（A驱动器），硬盘则用 0x80
                   ; 若用硬盘，需改为 mov dl, 0x80

; 柱面计数：最多读 10 个柱面
mov byte [cyl_cnt], 10  

readloop:          
mov si, 0          ; 重置重试计数器（SI 记录当前扇区失败次数）

retry:             
; 调用 BIOS 读扇区中断
mov ah, 0x02       ; 功能号 0x02 = 读扇区
mov al, 1          ; 每次读 1 个扇区
mov bx, 0          ; 目标地址：ES:BX = 0x0820:0x0000
int 0x13           ; 触发硬盘/软盘中断
jnc next           ; CF=0（成功）则跳转到 next

; 读取失败：重试逻辑
add si, 1          ; 失败次数 +1
cmp si, 5          ; 超过 5 次？
jae error          ; 是 → 报错

; 重置驱动器后重试
mov ah, 0x00       ; 功能号 0x00 = 重置驱动器
int 0x13           ; 重置 DL 指定的设备
jmp retry          ; 回到 retry 再次尝试

next:              

; 移动内存地址：下一个扇区存放到 +512 字节处
mov ax, es         
add ax, 0x0020     ; 段地址 +0x20 → 物理地址 +512（0x20*16=0x200）
mov es, ax         

; 更新 CHS 地址，准备读下一个扇区
add cl, 1          ; 扇区号 +1
cmp cl, 18         ; 扇区是否超过 18？
jbe readloop       ; 没超过 → 继续读当前柱面/磁头的下一个扇区

; 扇区超过 18，切换磁头
mov cl, 2          ; 扇区重置为 2（下一个磁头的起始扇区）
inc dh             ; 磁头号 +1
cmp dh, 2          ; 磁头是否超过 2（一般硬盘/软盘只有 0、1 两个磁头）
jb readloop        ; 没超过 → 读下一个磁头的扇区

; 磁头超过 2，切换柱面
mov dh, 0          ; 磁头重置为 0
inc ch             ; 柱面号 +1

; 检查是否读完 10 个柱面
mov si, tmsg  
call putstr   
dec byte [cyl_cnt] 
jnz readloop       ; 若未读完 10 个柱面 → 继续读下一个柱面


; （所有柱面读取完成后，跳转执行系统代码）
jmp 0x0820:0x0000  


; --------------------------
; 错误处理
; --------------------------
error:             
mov si, msg_err    
call putstr        
hlt                
jmp $              


; --------------------------
; 辅助函数：打印字符串（SI=字符串地址）
; --------------------------
putstr:            
mov ah, 0x0e       ; BIOS 功能号：Teletype 输出
.put_char:         
mov al, [si]       
inc si             
cmp al, 0          
je .put_end        
int 0x10           
jmp .put_char      
.put_end:          
ret                


; --------------------------
; 数据区
; --------------------------
msg_boot: db "Booting...", 0x0d, 0x0a, 0  
tmsg: db "test msg", 0x0d, 0x0a, 0  
msg_err:  db "Error!", 0x0d, 0x0a, 0      
cyl_cnt:  db 0     ; 柱面计数器（初始由代码设为10）


; --------------------------
; 启动扇区填充
; --------------------------
times 510 - ($ - $$) db 0  
dw 0xaa55            ; 启动标志